package com.shisan.tingshu.album.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import com.shisan.tingshu.album.mapper.AlbumInfoMapper;
import com.shisan.tingshu.album.mapper.TrackInfoMapper;
import com.shisan.tingshu.album.mapper.TrackStatMapper;
import com.shisan.tingshu.album.service.TrackInfoService;
import com.shisan.tingshu.album.service.VodService;
import com.shisan.tingshu.common.constant.SystemConstant;
import com.shisan.tingshu.common.execption.ShisanException;
import com.shisan.tingshu.common.result.Result;
import com.shisan.tingshu.common.util.AuthContextHolder;
import com.shisan.tingshu.model.album.AlbumInfo;
import com.shisan.tingshu.model.album.TrackInfo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shisan.tingshu.model.album.TrackStat;
import com.shisan.tingshu.query.album.TrackInfoQuery;
import com.shisan.tingshu.user.client.UserInfoFeignClient;
import com.shisan.tingshu.vo.album.*;
import com.shisan.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private VodService vodService;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    /**
     * 上传声音
     *
     * @param file
     * @return
     */
    @Override
    public Map<String, Object> uploadTrack(MultipartFile file) {

        return vodService.uploadTack(file);
    }

    /**
     * 保存声音
     *
     * @param trackInfoVo
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {

        TrackInfoServiceImpl proxyObject = (TrackInfoServiceImpl) AopContext.currentProxy();

        // 保存声音基本信息
        TrackInfo trackInfo = new TrackInfo();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        trackInfo.setUserId(AuthContextHolder.getUserId());
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS); // 声音默认审核通过
        // 处理声音的orderNum（即该声音在当前专辑中的序列号）
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TrackInfo::getAlbumId, trackInfoVo.getAlbumId());
        wrapper.orderByDesc(TrackInfo::getOrderNum);
        wrapper.last("limit 1");
        TrackInfo trackInfo1 = trackInfoMapper.selectOne(wrapper);
        Integer orderNum = trackInfo1 == null ? 1 : trackInfo1.getOrderNum() + 1;
        trackInfo.setOrderNum(orderNum);

        // 处理声音媒体信息
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        if (trackMediaInfoVo == null) {
            throw new ShisanException(201, "该声音对应的媒体信息不存在");
        }
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
        trackInfo.setMediaType(trackMediaInfoVo.getType());
        trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
        int insert = trackInfoMapper.insert(trackInfo);
        log.info("保存声音媒体信息：{}", insert > 0 ? "成功" : "失败");

        // 保存声音统计信息
        Integer integer = proxyObject.saveTrackStat(trackInfo.getId());
        log.info("保存声音统计信息：{}", integer > 0 ? "成功" : "失败");

        // 反向更新专辑的包含声音集数属性
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new ShisanException(201, "该声音对应的专辑不存在");
        }
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        int i = albumInfoMapper.updateById(albumInfo);
        log.info("更新对应专辑: {}", i > 0 ? "成功" : "失败");
    }

    /**
     * 分页展示用户创建的声音列表
     *
     * @param pageParam
     * @param trackInfoQuery
     * @return
     */
    @Override
    public IPage<TrackListVo> findUserTrackPage(IPage<TrackListVo> pageParam, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.findUserTrackPage(pageParam, trackInfoQuery);
    }

    /**
     * 修改声音
     *
     * @param trackId
     * @param trackInfoVo
     */
    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        // 修改 track_info 表
        // 先查询声音的旧信息
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (trackInfo == null) {
            throw new ShisanException(201, "该声音不存在");
        }
        // 修改声音的媒体信息
        String mediaFileIdNew = trackInfoVo.getMediaFileId();
        if (StringUtils.isEmpty(mediaFileIdNew)) {
            throw new ShisanException(201, "新上传的声音媒体信息不存在");
        }
        // 获取到声音的旧媒体信息
        String mediaFileIdOld = trackInfo.getMediaFileId();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // 如果新上传的声音媒体信息与旧媒体信息不一致，重新上传声音媒体信息
        if (!StringUtils.isEmpty(mediaFileIdNew) && !mediaFileIdNew.equals(mediaFileIdOld)) {
            // 修改声音的时候 重新上传一个新声音
            TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(mediaFileIdNew);
            if (trackMediaInfoVo == null) {
                throw new ShisanException(201, "上传的新声音不存在");
            }

            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
            trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
        }

        trackInfoMapper.updateById(trackInfo);
    }

    /**
     * 根据声音id删除声音
     *
     * @param trackId
     */
    @Override
    public void removeTrackInfo(Long trackId) {
        // 修改该声音对应专辑的声音集数
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (trackInfo == null) {
            throw new ShisanException(201, "该声音已经不存在");
        }
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new ShisanException(201, "该声音对应的专辑不存在");
        }
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);

        // 删除声音基本信息
        trackInfoMapper.deleteById(trackId);
        // 删除声音统计信息
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
        // 删除vod中的声音（同时删除磁盘中临时目录的文件）
        vodService.removeMediaFile(trackInfo.getMediaFileId());

    }

    /**
     * 根据专辑id查询该专辑下声音列表并显示付费图标
     *
     * @param albumTrackListVoPage
     * @param albumId
     * @return
     */
    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(IPage<AlbumTrackListVo> albumTrackListVoPage, Long albumId) {

        IPage<AlbumTrackListVo> result = new Page<AlbumTrackListVo>();

        // 查询该专辑
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new ShisanException(201, "该专辑不存在");
        }

        // 分页查询该专辑下的声音列表
        albumTrackListVoPage = trackInfoMapper.getAlbumTrackListByAlbumIdFromDb(albumTrackListVoPage, albumId);

        // 查询专辑的其它信息
        String payType = albumInfo.getPayType(); // 免费、vip免费、付费
        String priceType = albumInfo.getPriceType(); // 单集、整专辑
        Integer tracksForFree = albumInfo.getTracksForFree(); // 声音的集数
        Long userId = AuthContextHolder.getUserId();

        switch (payType) {
            case "0101":
                // 处理免费类型
                result = albumTrackListVoPage;
                break;
            case "0102":
                // 处理vip免费类型
                result = dealAlbumPayTypeVip(albumId, userId, priceType, tracksForFree, albumTrackListVoPage);
                break;
            case "0103":
                // 处理付费类型
                result = dealAlbumPayTypeNeedPay(albumId, userId, priceType, tracksForFree, albumTrackListVoPage);
        }

        return result;
    }

    /**
     * 处理付费类型
     *
     * @param albumId
     * @param userId
     * @param priceType
     * @param tracksForFree
     * @param albumTrackListVoPage
     * @return
     */
    private IPage<AlbumTrackListVo> dealAlbumPayTypeNeedPay(Long albumId, Long userId, String priceType, Integer tracksForFree, IPage<AlbumTrackListVo> albumTrackListVoPage) {
        // 判断用户id是否存在。不存在说明没有登录，展示免费5集的声音
        if (userId == null) {
            List<AlbumTrackListVo> albumTrackListVoList = albumTrackListVoPage.getRecords()
                    .stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() <= 5).collect(Collectors.toList());
            return albumTrackListVoPage.setRecords(albumTrackListVoList);
        }
        // 用户登录了
        return getReallyShowAlbumTrackList(albumId, userId, priceType, tracksForFree, albumTrackListVoPage);
    }

    /**
     * 根据声音id查询声音的统计信息
     *
     * @param trackId
     * @return
     */
    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackStatMapper.getTrackStatVo(trackId);
    }

    /**
     * 根据声音id集合，查询声音对象集合
     *
     * @param trackIdList
     * @return
     */
    @Override
    public List<TrackListVo> getTrackListByIds(List<Long> trackIdList) {

        List<TrackInfo> trackInfos = trackInfoMapper.selectBatchIds(trackIdList);
        return trackInfos.stream().map(trackInfo -> {
            TrackListVo trackListVo = new TrackListVo();
            BeanUtils.copyProperties(trackInfo, trackListVo);
            trackListVo.setTrackId(trackInfo.getId());
            return trackListVo;
        }).collect(Collectors.toList());
    }

    /**
     * 分集展示要买的声音列表
     *
     * @param currentTrackId
     * @return
     */
    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long currentTrackId) {

        ArrayList<Map<String, Object>> result = new ArrayList<>();
        Long userId = AuthContextHolder.getUserId();
        // 1.根据声音id，查询声音是否存在
        TrackInfo trackInfo = trackInfoMapper.selectById(currentTrackId);
        if (trackInfo == null) {
            throw new ShisanException(201, "当前声音不存在");
        }
        // 2.根据专辑id，查询专辑是否存在
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new ShisanException(201, "该声音对应的专辑不存在");
        }
        // 3.获取专辑的价格（如果价格类型（即AlbumInfo中的priceType字段）是整专辑的话，该字段的值就是专辑的价格；如果价格类型是单集的话，该字段的值就是声音的价格）
        BigDecimal trackPrice = albumInfo.getPrice();
        // 4.获取当前声音的序列号
        Integer orderNum = trackInfo.getOrderNum();
        // 5.查询当前声音后的50集用于展示
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TrackInfo::getAlbumId, albumId);
        wrapper.gt(TrackInfo::getOrderNum, orderNum);
        wrapper.last("limit  50");
        wrapper.orderByAsc(TrackInfo::getOrderNum);
        List<TrackInfo> trackInfos = trackInfoMapper.selectList(wrapper);
        // 6.查询当前用户买过指定专辑下的哪些声音
        Result<Map<Long, String>> userPaidAlbumTrack = userInfoFeignClient.getUserPaidAlbumTrack(userId, albumId);
        Map<Long, String> userPaidAlbumTrackData = userPaidAlbumTrack.getData();
        if (userPaidAlbumTrackData == null) {
            throw new ShisanException(201, "远程调用用户微服务，获取用户购买过指定专辑下的哪些声音失败");
        }
        // 7.将买过的声音过滤掉，得到没有买过的声音
        List<TrackInfo> reallyShowTrackList = trackInfos.stream()
                .filter(trackInfo1 -> StringUtils.isEmpty(userPaidAlbumTrackData.get(trackInfo1.getId())))
                .collect(Collectors.toList());
        // 8.展示可供购买的声音列表
        // 8.1 展示本集
        Map<String, Object> currentMap = new HashMap<>();
        currentMap.put("name", "本集");
        currentMap.put("price", trackPrice);
        currentMap.put("trackCount", 0); // 0只是本集的标识
        result.add(currentMap);
        // 8.2 展示后n集，以10集为一块。比如23集->3块（map）、20集->2块
        int reallyShowTrackSize = reallyShowTrackList.size();
        int block = reallyShowTrackSize % 10 == 0 ? reallyShowTrackSize / 10 : reallyShowTrackSize / 10 + 1;
        for (int i = 1; i <= block; i++) {
            int blockSize = i * 10;
            if (blockSize >= reallyShowTrackSize) {
                // 构建Map对象
                Map<String, Object> lastMap = new HashMap<>();
                lastMap.put("name", "后" + reallyShowTrackSize + "集");
                lastMap.put("price", trackPrice.multiply(new BigDecimal(reallyShowTrackSize)));
                lastMap.put("trackCount", reallyShowTrackSize);
                result.add(lastMap);
                break;
            }
            // 构建Map对象
            Map<String, Object> otherMap = new HashMap<>();
            otherMap.put("name", "后" + blockSize + "集");
            otherMap.put("price", trackPrice.multiply(new BigDecimal(blockSize)));
            otherMap.put("trackCount", blockSize);
            result.add(otherMap);
        }

        return result;
    }

    /**
     * 查询指定集数的声音列表
     * @param userId
     * @param trackId
     * @param trackCount
     * @return
     */
    @Override
    public List<TrackInfo> getTrackListByCurrentTrackId(Long userId, Long trackId, Integer trackCount) {

        List<TrackInfo> result = new ArrayList<>();
        // 1.判断声音对象
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (trackInfo == null) {
            throw new ShisanException(201, "该声音不存在");
        }
        // 2.查询该声音对应的专辑id
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new ShisanException(201, "该声音对应的专辑不存在");
        }
        // 3.判断当前买的声音是本集还是其它集
        if (trackCount == 0) {
            // 本集
            result.add(trackInfo);
        } else {
            // 其它集
            LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(TrackInfo::getAlbumId, albumId);
            wrapper.gt(TrackInfo::getOrderNum, trackInfo.getOrderNum());
            wrapper.last("limit " + trackCount);
            wrapper.orderByAsc(TrackInfo::getOrderNum);
            result = trackInfoMapper.selectList(wrapper);
        }
        return result;
    }

    /**
     * 处理vip免费类型
     *
     * @param albumId
     * @param userId
     * @param priceType
     * @param tracksForFree
     * @param albumTrackListVoPage
     * @return
     */
    private IPage<AlbumTrackListVo> dealAlbumPayTypeVip(Long albumId,
                                                        Long userId,
                                                        String priceType,
                                                        Integer tracksForFree,
                                                        IPage<AlbumTrackListVo> albumTrackListVoPage) {

        // 判断用户id是否存在。不存在说明没有登录，展示免费5集的声音
        if (userId == null) {
            List<AlbumTrackListVo> albumTrackListVoList = albumTrackListVoPage.getRecords()
                    .stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() <= 5).collect(Collectors.toList());
            return albumTrackListVoPage.setRecords(albumTrackListVoList);
        }
        // 用户id存在。判断该专辑下的声音哪些该展示付费图标，哪些不展示。VIP用户或者时普通用户买过的声音，不展示付费图标
        Result<UserInfoVo> userInfo = userInfoFeignClient.getUserInfo(userId);
        UserInfoVo userInfoData = userInfo.getData();
        if (userInfoData == null) {
            throw new ShisanException(201, "用户信息不存在");
        }
        Integer isVip = userInfoData.getIsVip(); // 0：不是vip 1：是vip
        Date vipExpireTime = userInfoData.getVipExpireTime(); // vip过期时间
        // 判断是否是vip
        if ("0".equals(isVip + "") || ("1".equals(isVip + "") && vipExpireTime.before(new Date()))) { // 如果不是vip，或者vip过期了
            return getReallyShowAlbumTrackList(albumId, userId, priceType, tracksForFree, albumTrackListVoPage);
        } else { // 如果是vip且还没过期
            return albumTrackListVoPage;
        }
    }

    /**
     * 判断是单集购买还是整专辑购买
     *
     * @param albumId
     * @param userId
     * @param priceType
     * @param tracksForFree
     * @param albumTrackListVoPage
     * @return
     */
    private IPage<AlbumTrackListVo> getReallyShowAlbumTrackList(Long albumId,
                                                                Long userId,
                                                                String priceType,
                                                                Integer tracksForFree,
                                                                IPage<AlbumTrackListVo> albumTrackListVoPage) {
        if ("0201".equals(priceType)) { // 如果是单集购买
            // 查询当前用户购买过当前专辑下的哪些声音
            Result<Map<Long, String>> userPaidAlbumTrackMap = userInfoFeignClient.getUserPaidAlbumTrack(userId, albumId);
            Map<Long, String> userPaidAlbumTrackMapData = userPaidAlbumTrackMap.getData();
            if (userPaidAlbumTrackMapData == null) {
                throw new ShisanException(201, "远程调用用户微服务，获取该用户购买过专辑下的哪些声音失败");
            }
            List<AlbumTrackListVo> reallyShowAlbumTrackList = albumTrackListVoPage.getRecords().stream().map(albumTrackListVo -> {
                // 如果该用户购买过该集声音，那么这一集声音的付费图标就不用显示（使用默认的）
                // 反之如果这集声音，该用户没有买过且还不在免费集数之内那么就要展示付费图标
                if (StringUtils.isEmpty(userPaidAlbumTrackMapData.get(albumTrackListVo.getTrackId())) && albumTrackListVo.getOrderNum() > tracksForFree) {
                    albumTrackListVo.setIsShowPaidMark(true);
                }
                return albumTrackListVo;
            }).collect(Collectors.toList());
            return albumTrackListVoPage.setRecords(reallyShowAlbumTrackList);
        } else { // 如果是整专辑购买
            Result<Boolean> userPaidAlbum = userInfoFeignClient.getUserPaidAlbum(userId, albumId);
            Boolean isPaidAlbum = userPaidAlbum.getData();
            if (isPaidAlbum == null) {
                throw new ShisanException(201, "远程调用用户微服务，获取该用户是否购买过该专辑失败");
            }
            if (isPaidAlbum) { // 如果购买了整张专辑
                return albumTrackListVoPage;
            }
            // 如果没有购买该专辑
            List<AlbumTrackListVo> reallyShowAlbumTrackList = albumTrackListVoPage.getRecords().stream().map(albumTrackListVo -> {
                if (albumTrackListVo.getOrderNum() > tracksForFree) {
                    albumTrackListVo.setIsShowPaidMark(true);
                }
                return albumTrackListVo;
            }).collect(Collectors.toList());
            return albumTrackListVoPage.setRecords(reallyShowAlbumTrackList);
        }
    }


    @Transactional
    public Integer saveTrackStat(Long trackId) {
        ArrayList<String> trackStatus = new ArrayList<>();
        trackStatus.add(SystemConstant.TRACK_STAT_PLAY);
        trackStatus.add(SystemConstant.TRACK_STAT_COLLECT);
        trackStatus.add(SystemConstant.TRACK_STAT_PRAISE);
        trackStatus.add(SystemConstant.TRACK_STAT_COMMENT);
        try {
            for (String status : trackStatus) {
                TrackStat trackStat = new TrackStat();
                trackStat.setTrackId(trackId);
                trackStat.setStatType(status);
                trackStat.setStatNum(0);
                trackStatMapper.insert(trackStat);
            }
            return 1;
        } catch (Exception e) {
            return 0;
        }
    }
}
